package com.ssy.jt808.gateway.util;

/**
 * @author wangzezhou
 */

import lombok.extern.slf4j.Slf4j;

import java.net.*;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;

/**
 * 获取本机IP 地址
 *
 * @author wangzezhou
 */
@Slf4j
public class LocalIpUtils{

  /**
   * 获取本机所有网卡信息   得到所有IP信息
   *
   * @return Inet4Address>
   */
  public static List<Inet4Address> getLocalIp4AddressFromNetworkInterface() throws SocketException{

    // 所有网络接口信息
    Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
    List<Inet4Address> addresses = new ArrayList<>();
    while(networkInterfaces.hasMoreElements()){
      NetworkInterface networkInterface = networkInterfaces.nextElement();

      //滤回环网卡、点对点网卡、非活动网卡、虚拟网卡并要求网卡名字是eth或ens开头
      if( !isValidInterface(networkInterface) ){
        continue;
      }

      // 所有网络接口的IP地址信息
      Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
      while(inetAddresses.hasMoreElements()){
        InetAddress inetAddress = inetAddresses.nextElement();

        // 判断是否是IPv4，并且内网地址并过滤回环地址.
        if( isValidAddress(inetAddress) ){
          addresses.add((Inet4Address)inetAddress);
        }
      }
    }
    return addresses;
  }

  /**
   * 过滤回环网卡、点对点网卡、非活动网卡、虚拟网卡并要求网卡名字是eth或ens开头
   *
   * @param ni 网卡
   *
   * @return 如果满足要求则true，否则false
   */
  private static boolean isValidInterface( NetworkInterface ni ) throws SocketException{
    return !ni.isLoopback() && !ni.isPointToPoint() && ni.isUp() && !ni.isVirtual();
  }

  /**
   * 判断是否是IPv4，并且内网地址并过滤回环地址.
   */
  private static boolean isValidAddress( InetAddress address ){
    return address instanceof Inet4Address && address.isSiteLocalAddress() && !address.isLoopbackAddress();
  }

  /**
   * 通过Socket 唯一确定一个IP
   * 当有多个网卡的时候，使用这种方式一般都可以得到想要的IP。
   *
   * @return Inet4Address>
   */
  public static Inet4Address getIpBySocket( String host, int port ){
    try(final DatagramSocket socket = new DatagramSocket()){
      socket.connect(InetAddress.getByName(host), port);
      if( socket.getLocalAddress() instanceof Inet4Address ){
        return (Inet4Address)socket.getLocalAddress();
      }
    } catch(UnknownHostException|SocketException e){
      log.error(MessageFormat.format("连接{0},{1}获取本地IP发生异常", host, port), e);
    }
    return null;
  }

  /**
   * 获取本地IPv4地址
   *
   * @return Inet4Address>
   */
  public static Inet4Address getLocalIp4Address() throws SocketException{
    final List<Inet4Address> inet4Addresses = getLocalIp4AddressFromNetworkInterface();
    if( inet4Addresses.size() > 0 ){
      return getIpBySocket("218.85.157.99", 80);
    }

    return null;
  }

  /**
   * 获取本地 IP 地址字符串
   * @param host
   * @param port
   * @return
   */
  public static String getLocalIp4String( String host, int port ){

    Inet4Address ip4Address = getIpBySocket(host, port);
    if( !Objects.isNull(ip4Address) ){
      return ip4Address.getHostAddress();
    }

    return null;
  }

}
